﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;

using ProjectBase.Core;
using ProjectBase.Core.Web;
using ProjectBase.Mvc;

using Survey.Common;
using Survey.Common.Business;
using Survey.Common.Business.Services;
using Survey.Entity;
using Survey.Entity.Services;

namespace Survey.Business.Services
{
    /// <summary>
    ///     All Business checks for 'Node' on CRUD operations
    ///     are nested and encapsulated in this NodeFacade
    /// </summary>
    public class StoryNodeFacade : Facade, IStoryNodeFacade
    {
        #region members
        protected const string Href = "Story/Article";

        class Const
        {
            public const string IDSeparator = "_";
        }
        #endregion members

        #region constructor
        static StoryNodeFacade()
        {
            Services.ArticleFacade.ChangeHandler += ClearRoot;

            Business.ArticleCategoryFacade.ChangeHandler += ClearRoot;
            Business.ArticleGroupFacade.ChangeHandler += ClearRoot;
        }
        #endregion constructor

        #region INodeFacade
        public virtual IEnumerable<ITVDataItem> GetRootNodes()
        {
            return GetTVSource().Where(n => n.ParentId.IsNull());
        }

        public virtual ITVDataItem GetNode(string id)
        {
            return GetTVSource().Where(n => n.ID.Equals(id)).SingleOrDefault();
        }
        #endregion INodeFacade

        #region TreeView source
        protected virtual IEnumerable<ITVDataItem> GetTVSource()
        {
            var nodes = Nodes;
            if (nodes.IsNull())
            {
                nodes = LoadArticles();
                Nodes = nodes;
            }
            return nodes;
        }

        protected virtual IEnumerable<ITVDataItem> LoadArticles()
        {
            var filter = new ArticleFilter
            {
                MaxRowsPerPage = 999,
                IsVisible = true,
            };
            filter.PropertyList[Str.Common.ID] = null;
            filter.PropertyList[Str.Common.Code] = null;

            filter.PropertyList["ArticleCategory.ID"] = "ArticleCategoryId";
            filter.PropertyList["ArticleGroup.ID"] = "ArticleGroupId";
            filter.PropertyList["Title"] = null;
            filter.PropertyList["Description"] = null;

            filter.OrderBy["ArticleCategory.ID"] = true;
            filter.OrderBy["ArticleGroup.ID"] = true;


            var list = new List<ITVDataItem>();
            var data = ArticleFacade.Find(filter);

            CreateLevel1(data, list);

            return list;
        }

        protected virtual void CreateLevel1(IEnumerable<ITVSource> data, List<ITVDataItem> list)
        {
            foreach (var categoryId in data.Select(e => e.ArticleCategoryId).Distinct())
            {
                // I. category
                var category = ArticleCategoryFacade.GetById(categoryId);
                if (category.Code.Equals(Str.Business.CodeLists.Any))
                {
                    continue; // 'Any - Not Selected' is not
                }
                var node = new StoryNode
                {
                    ID = category.Code,
                    ParentId = null,
                    Href = Href,
                    Text = category.Name,
                    RouteValues =
                        new Dictionary<string, object> { { "category", category.Code } },
                };
                list.Add(node);

                // II. groups
                CreateLevel2(data.Where(e => e.ArticleCategoryId.Equals(category.ID)), category, list, node);
            }
        }

        protected virtual void CreateLevel2(IEnumerable<ITVSource> data, ArticleCategory category,
            List<ITVDataItem> list, StoryNode parent)
        {
            var anyArticleGroup = ArticleGroupFacade.GetByCode(Str.Business.CodeLists.Any);

            // A) ArticleGroup Is()
            var groups = new List<ITVDataItem>();
            foreach (var groupId in data.Where(e => !e.ArticleGroupId.Equals(anyArticleGroup.ID))
                .Select(e => e.ArticleGroupId)
                .Distinct())
            {
                var group = ArticleGroupFacade.GetById(groupId);
                var child = new StoryNode
                {
                    ID = parent.ID + Const.IDSeparator + group.Code,
                    ParentId = parent.ID,
                    Href = Href,
                    Text = group.Name,
                    RouteValues =
                        new Dictionary<string, object>
                        {
                            {"category", category.Code},
                            {"group", group.Code}
                        },
                };
                groups.Add(child);
                list.Add(child);

                // III. projectNames
                CreateLevel3(data.Where(e => e.ArticleGroupId.Equals(group.ID)), list, child);
            }

            // B) ArticleGroup is ANY
            foreach (var article in data.Where(e => e.ArticleGroupId.Equals(anyArticleGroup.ID)))
            {
                var child = new StoryNode
                {
                    ID = parent.ID + Const.IDSeparator + article.Code,
                    ParentId = parent.ID,
                    Href = Href,
                    Text = article.Title,
                    RouteValues =
                        new Dictionary<string, object>
                        {
                            {"category", string.Empty},
                            {"group", string.Empty},
                            {Str.Common.Code, article.Code}
                        },
                };
                groups.Add(child);
                list.Add(child);
            }


            parent.Items = groups;
        }

        protected virtual void CreateLevel3(IEnumerable<ITVSource> data, List<ITVDataItem> list, StoryNode parent)
        {
            var articles = new List<ITVDataItem>();
            foreach (var article in data)
            {
                var child = new StoryNode
                {
                    ID = parent.ID + Const.IDSeparator + article.Code,
                    ParentId = parent.ID,
                    Href = Href,
                    Text = article.Title,
                    RouteValues = new Dictionary<string, object>
                    {
                        {Str.Controllers.ArticleCategory, string.Empty},
                        {Str.Controllers.ArticleGroup, string.Empty},
                        {Str.Common.Code, article.Code}
                    },
                };

                articles.Add(child);
                list.Add(child);
            }
            parent.Items = articles;
        }
        #endregion TreeView source

        #region static root nodes
        protected static readonly object Locker = new object();

        protected static IEnumerable<ITVDataItem> Nodes { get; set; }

        public static void ClearRoot(object sender, EventArgs args)
        {
            lock (Locker)
            {
                Nodes = null;
            }
        }
        #endregion static root nodes

        #region properties
        /// <summary>
        ///     Access to the complete list of articles
        /// </summary>
        public virtual IArticleFacade ArticleFacade { protected get; set; }

        /// <summary>
        ///     Allowes LAZILY use ArticleCategoryFacade (get) or Ioc (set)
        /// </summary>
        public virtual IArticleCategoryFacade ArticleCategoryFacade { protected get; set; }

        /// <summary>
        ///     Allowes LAZILY use ArticleGroupFacade (get) or Ioc (set)
        /// </summary>
        public virtual IArticleGroupFacade ArticleGroupFacade { protected get; set; }
        #endregion properties
    }
}